package frontend.pages.reports.base;

import frontend.components.form.ValidatableForm;
import frontend.model.reports.ReportInputUIModel;
import shared.util.CalendarUtils;
import frontend.components.base.ComponentFactory;
import org.apache.log4j.Logger;
import org.apache.wicket.Localizer;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.validation.ValidationError;

import java.io.Serializable;
import java.util.*;

public abstract class AbstractReportForm<T extends Serializable & Comparable> extends ValidatableForm<ReportInputUIModel> {
    private static Logger logger = Logger.getLogger(AbstractReportForm.class);

    public static final String RESOURCE_KEY_FIELD_LABEL_START_DATE = "pages.defaultReport.form.startDate";
    public static final String RESOURCE_KEY_FIELD_LABEL_END_DATE = "pages.defaultReport.form.endDate";

    private static final String RESOURCE_KEY_VALIDATION_END_DATE_AFTER_START_DATE = "validation.form.report.endDateAfterEndDate";

    private List<T> reportResults = new ArrayList<T>();
    private WebMarkupContainer workLogListContainer;
    protected AjaxButton showReportResultsButton;

    public AbstractReportForm(String id, ReportInputUIModel model, List<T> reportResults,
                              WebMarkupContainer workLogListContainer) {
        super(id,  model);
        this.reportResults = reportResults;
        this.workLogListContainer = workLogListContainer;
    }

    protected void constructFormContent() {
        populateDefaultDates();
        Panel startDate = ComponentFactory.createDatePickerComponent("startDate", RESOURCE_KEY_FIELD_LABEL_START_DATE, uiModel);
        Panel endDate = ComponentFactory.createDatePickerComponent("endDate", RESOURCE_KEY_FIELD_LABEL_END_DATE, uiModel);
        showReportResultsButton = createReportResultsButton();

        add(startDate, endDate, showReportResultsButton);
        addAdditionalFilteringComponents();
    }

    private void populateDefaultDates() {
        uiModel.setStartDate(CalendarUtils.getFirstDayOfTheMonthAsDate());
        uiModel.setEndDate(new Date());
    }

    protected abstract void addAdditionalFilteringComponents();

    private AjaxButton createReportResultsButton() {
        AjaxButton showWorkLogButton = new AjaxButton("showReportResults", this) {
            @Override
            protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
                generateReportResult(target);
            }

            @Override
            protected void onError(AjaxRequestTarget target, Form<?> form) {
                logger.error("Error occurred while submitting form.");
            }
        };
        return showWorkLogButton;
    }

    private void generateReportResult(AjaxRequestTarget target) {
        validationErrors.clear();
        doFormValidation();

        if (validationErrors.size() > 0) {
            for (ValidationError validationError : validationErrors) {
                error(validationError.getMessage());
            }
        } else {
            reportResults.clear();
            List<T> reportEntriesFromDB = retrieveReportDataFromDatabase();
            Collections.sort(reportEntriesFromDB);
            if (reportEntriesFromDB != null) {
                reportResults.addAll(reportEntriesFromDB);
                if (workLogListContainer.getParent() instanceof AbstractWorklogReportPanel) {
                    ((AbstractWorklogReportPanel)workLogListContainer.getParent()).updateTotalHoursModel();
                }
                ((AbstractReportPanel)(workLogListContainer.getParent())).updateTotalRecordsModel();
            }
            if (reportResults.size() == 0) {
                feedbackPanel.error(Localizer.get().getString("report.table.noResults", null));
            }
            target.add(workLogListContainer);
            target.add(workLogListContainer.getParent());
        }
        target.add(feedbackPanel);
    }

    protected void hideResultsContainers(AjaxRequestTarget target) {
        workLogListContainer.setVisible(false);
        target.add(workLogListContainer);
    }

    protected abstract List<T> retrieveReportDataFromDatabase();

    @Override
    protected void doFormValidation() {
        validateNotEmpty(uiModel.getStartDate(), RESOURCE_KEY_FIELD_LABEL_START_DATE);
        validateNotEmpty(uiModel.getEndDate(), RESOURCE_KEY_FIELD_LABEL_END_DATE);
        validateEndDateIsAfterStartDate(uiModel.getStartDate(), uiModel.getEndDate());
    }

    private void validateEndDateIsAfterStartDate(Date startDate, Date endDate) {
        if (startDate!= null && endDate != null && startDate.after(endDate)) {
            addFieldValidationError(RESOURCE_KEY_FIELD_LABEL_START_DATE, RESOURCE_KEY_VALIDATION_END_DATE_AFTER_START_DATE);
        }
    }
}